﻿using System;
using System.Net;
using System.Linq;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using JXT.PrimaryKey.Batman.Container;

namespace JXT.PrimaryKey.Batman.Core.WcfService
{
    public class ErrorHandlerBehavior : IServiceBehavior, IContractBehavior
    {
        // Fields
        private IErrorHandler _errorHandler;
        public const string HttpRequestInformationProperty = "HttpRequestInformation";

        // Methods
        public ErrorHandlerBehavior(Type type)
        {
            this._errorHandler = (IErrorHandler)Activator.CreateInstance(type);
        }

        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
            {
                if (!dispatcher.ErrorHandlers.Contains(this._errorHandler)) dispatcher.ErrorHandlers.Add(this._errorHandler);
                foreach (EndpointDispatcher dispatcher2 in dispatcher.Endpoints)
                {
                    if (dispatcher2.DispatchRuntime.MessageInspectors.FirstOrDefault<IDispatchMessageInspector>(i => (i.GetType() == typeof(HttpRequestInformationInspector))) == null) dispatcher2.DispatchRuntime.MessageInspectors.Add(new HttpRequestInformationInspector());
                }
            }
        }

        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
        {
            if (!dispatchRuntime.ChannelDispatcher.ErrorHandlers.Contains(this._errorHandler)) dispatchRuntime.ChannelDispatcher.ErrorHandlers.Add(this._errorHandler);
            foreach (EndpointDispatcher dispatcher in dispatchRuntime.ChannelDispatcher.Endpoints)
            {
                if (dispatcher.DispatchRuntime.MessageInspectors.FirstOrDefault<IDispatchMessageInspector>(i => (i.GetType() == typeof(HttpRequestInformationInspector))) == null) dispatcher.DispatchRuntime.MessageInspectors.Add(new HttpRequestInformationInspector());
            }
        }

        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }

        // Nested Types
        private class HttpRequestInformationInspector : IDispatchMessageInspector
        {
            // Methods
            public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
            {
                if (!OperationContext.Current.OutgoingMessageProperties.ContainsKey(HttpRequestInformationProperty))
                {
                    long num;
                    RequestInformation property = new RequestInformation();
                    string str = WebOperationContext.Current.IncomingRequest.Headers[HttpRequestHeader.ContentLength];
                    if (!string.IsNullOrEmpty(str))
                        long.TryParse(str, out num);
                    else
                        num = -1;
                    property.ContentLength = num;
                    property.Uri = OperationContext.Current.IncomingMessageHeaders.To;
                    property.Method = WebOperationContext.Current.IncomingRequest.Method;
                    property.ContentType = WebOperationContext.Current.IncomingRequest.ContentType;
                    property.Accept = WebOperationContext.Current.IncomingRequest.Accept;
                    property.UserAgent = WebOperationContext.Current.IncomingRequest.UserAgent;
                    property.Headers = WebOperationContext.Current.IncomingRequest.Headers;
                    OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestInformationProperty, property);
                }
                return null;
            }

            public void BeforeSendReply(ref Message reply, object correlationState)
            {
            }
        }
    }


}
